#include "Empire.h"
#include "EmpireStrings.h"
#include "Output.h"
#include "Global.h"
#include "BbsControlData.h"
#include "Input.h"
#include "Users.h"
#include "OverlayManagement.h"
#include "EmpireCombat.h"

#include <stdio.h>
#include <unistd.h>
#include <device.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <stdlib.h>


#pragma code-name("EMPIRECODE");
#pragma rodata-name("EMPIRECODE");
#pragma data-name("EMPIREDATA");
#pragma bss-name("EMPIREBSS");

empireBuilding_t _empireBuildings[] =
{	// Type				Name		St	   Lm	 Gld    P	SY	LY	 GY		
	{ EB_LUMBERMILL, "Lumbermill",	100,    10,   200,  10, 0,   5,   0 },
	{ EB_MINE,		 "Mine",		10,	   100,   200,  10, 5,   0,   0 },
	{ EB_MARKET,	 "Market",		100,   100,   500,  20, 0,   0,  10 },
	{ EB_FOUNDRY,	 "Foundry",		1000,  500,  3000,  30, 0,   0,  30 },
	{ EB_BROTHEL,	 "Brothel",		500,  2000,  5000,  50, 0,   0,  60 },
	{ EB_PUB,		 "Pub",			1000, 4000, 10000, 100, 0,   0, 120 },
	{ EB_BANK,		 "Bank",		4000, 6000, 20000, 200, 0,   0, 200 }
};

char buffer[81];

void loadSettings(void);
void initSettings(void);
bool saveSettings(void);
bool loadPlayer(empirePlayer_t *player, int playerNumber);
bool initPlayer(void);
bool savePlayer(empirePlayer_t *player);
long calculateMight(empirePlayer_t *player);
void playGame(void);
void statsLine(void);

void enterEmpire(void)
{
	static int i;

	memset(&_currentEmpirePlayer, 0, sizeof(empirePlayer_t));

	outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), EMPIRE_ENTER_1);

	loadSettings();

	for(i = 0; i < EMPIRE_MAX_PLAYERS; ++i)
	{
		if(_empireSettings.players[i].userNumber ==
			_currentUser.usernumber)
		{
			if(!loadPlayer(&_currentEmpirePlayer, i))
			{
				return;
			}
			break;
		}
	}

	if(i == EMPIRE_MAX_PLAYERS)
	{
		if(!initPlayer())
		{
			outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), EMPIRE_GAME_FULL_1);
			return;
		}
	}

	playGame();
}

void production(void)
{
	static long availablePeasants;
	static long lumberjacks;
	static long miners;
	static long merchants;
	static long smiths;
	static long whores;
	static long bartenders;
	static long bankers;

	static long foodProduced;
	static long woodProduced;
	static long stoneProduced;
	static long goldProduced;

	static long peasantsFed;
	static long peasantsBorn;
	static long peasantsDied;

	availablePeasants = _currentEmpirePlayer.peasants;

	// Calculate peasants available for farming
	lumberjacks = _currentEmpirePlayer.lumbermills 
		* _empireBuildings[EB_LUMBERMILL].peasantsRequired;

	if(availablePeasants < lumberjacks) 
		lumberjacks = availablePeasants;

	availablePeasants -= lumberjacks;

	miners = _currentEmpirePlayer.mines 
		* _empireBuildings[EB_MINE].peasantsRequired;

	if(availablePeasants < miners) 
		miners = availablePeasants;

	availablePeasants -= miners;

	merchants = _currentEmpirePlayer.markets 
		* _empireBuildings[EB_MARKET].peasantsRequired;

	if(availablePeasants < merchants) 
		merchants = availablePeasants;

	availablePeasants -= merchants;

	smiths = _currentEmpirePlayer.foundries 
		* _empireBuildings[EB_FOUNDRY].peasantsRequired;

	if(availablePeasants < smiths) 
		smiths = availablePeasants;

	availablePeasants -= smiths;

	whores = _currentEmpirePlayer.brothels 
		* _empireBuildings[EB_BROTHEL].peasantsRequired;

	if(availablePeasants < whores) 
		whores = availablePeasants;

	availablePeasants -= whores;

	bartenders = _currentEmpirePlayer.pubs 
		* _empireBuildings[EB_PUB].peasantsRequired;

	if(availablePeasants < bartenders) 
		bartenders = availablePeasants;

	availablePeasants -= whores;

	bankers = _currentEmpirePlayer.banks 
		* _empireBuildings[EB_BANK].peasantsRequired;

	if(availablePeasants < bankers) 
		bankers = availablePeasants;

	availablePeasants -= bankers;

	// Calculate crop yield
	foodProduced = _currentEmpirePlayer.acres * availablePeasants;
	foodProduced = _currentEmpirePlayer.acres * 3 > foodProduced 
		? foodProduced 
		: _currentEmpirePlayer.acres * 3;
	_currentEmpirePlayer.food += foodProduced;

	// Calculate wood production
	woodProduced = lumberjacks * _empireBuildings[EB_LUMBERMILL].baseLumberYield;
	_currentEmpirePlayer.lumber += woodProduced;
	
	// Calculate stone production
	stoneProduced = miners * _empireBuildings[EB_MINE].baseStoneYield;
	_currentEmpirePlayer.stone += stoneProduced;

	// Calculate gold production
	goldProduced = 0;
	goldProduced += _currentEmpirePlayer.markets * _empireBuildings[EB_MARKET].baseGoldYield;
	goldProduced += _currentEmpirePlayer.foundries * _empireBuildings[EB_FOUNDRY].baseGoldYield;
	goldProduced += _currentEmpirePlayer.brothels * _empireBuildings[EB_BROTHEL].baseGoldYield;
	goldProduced += _currentEmpirePlayer.pubs * _empireBuildings[EB_PUB].baseGoldYield;
	goldProduced += _currentEmpirePlayer.banks * _empireBuildings[EB_BANK].baseGoldYield;
	goldProduced += (_currentEmpirePlayer.acres * _currentEmpirePlayer.taxRate) / 100;

	_currentEmpirePlayer.gold += goldProduced;

	// Feed the peasants
	if(_currentEmpirePlayer.food > _currentEmpirePlayer.peasants)
	{
		_currentEmpirePlayer.food -= _currentEmpirePlayer.peasants;
		peasantsFed = _currentEmpirePlayer.peasants;
	}
	else
	{
		peasantsFed = _currentEmpirePlayer.food;
		_currentEmpirePlayer.food = 0;
	}

	// Calculate peasant growth
	peasantsBorn = 0;
	if(peasantsFed == _currentEmpirePlayer.peasants)
	{
		peasantsBorn = ((peasantsFed / 10) * (100 - _currentEmpirePlayer.taxRate)) / 100;
	}

	// Calculate peasant deaths
	peasantsDied = 0;
	if(peasantsFed == _currentEmpirePlayer.peasants)
	{
		peasantsDied = (peasantsFed / 25) + ((peasantsFed / 25) * _currentEmpirePlayer.taxRate) / 100;
	}
	else
	{
		peasantsDied = _currentEmpirePlayer.peasants - peasantsFed;
	}

	_currentEmpirePlayer.peasants += peasantsBorn;
	_currentEmpirePlayer.peasants -= peasantsDied;

	// Report
	outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), EMPIRE_PROD_BANNER_1);

	sprintf(buffer, EMPIRE_PROD_FOOD, foodProduced);
	outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), buffer);

	sprintf(buffer, EMPIRE_PROD_WOOD, woodProduced);
	outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), buffer);

	sprintf(buffer, EMPIRE_PROD_STONE, stoneProduced);
	outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), buffer);

	sprintf(buffer, EMPIRE_PROD_GOLD, goldProduced);
	outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), buffer);

	outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), EMPIRE_PROD_BANNER_3);

	sprintf(buffer, EMPIRE_KINGDOM_FOOD, _currentEmpirePlayer.food);
	outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), buffer);

	sprintf(buffer, EMPIRE_KINGODM_WOOD, _currentEmpirePlayer.lumber);
	outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), buffer);

	sprintf(buffer, EMPIRE_KINGDOM_STONE, _currentEmpirePlayer.stone);
	outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), buffer);

	outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), EMPIRE_PROD_BANNER_4);

	sprintf(buffer, EMPIRE_FED, peasantsFed);
	outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), buffer);

	sprintf(buffer, EMPIRE_BORN, peasantsBorn);
	outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), buffer);

	sprintf(buffer, EMPIRE_DIED, peasantsDied);
	outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), buffer);

	outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), EMPIRE_PROD_BANNER_5);

	sprintf(buffer, EMPIRE_POPULATION, _currentEmpirePlayer.peasants);
	outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), buffer);

	outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), CRLF);
	pause(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM));
	return;
}

void listPlayers(void)
{
	static char i;
	outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), EMPIRE_LIST_PLAYERS_1);
	outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), EMPIRE_CONQUEST_PICK_2);
	for(i = 0; i < _empireSettings.numberOfPlayers; ++i)
	{
		sprintf(buffer, EMPIRE_CONQUEST_PICK_T, i+1, _empireSettings.players[i].kingdonName,
			_empireSettings.players[i].might, _empireSettings.players[i].acres);
		outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), buffer);
	}
	outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), EMPIRE_LIST_PLAYERS_2);
}

void startTurnMenu(void)
{
	outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), EMPIRE_NEW_TURN_1);
	sprintf(buffer, EMPIRE_NEW_TURN_2, _currentEmpirePlayer.turnsRemaining);
	outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), buffer);
}

bool startTurn(void)
{
	static char key;

	startTurnMenu();

	while((key = tolower(inputChar(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), IO_ALPHA))) != 'q'
		&& key != 'c')
	{
		if(key == 'l') 
		{
			outputCharacter(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), key);
			listPlayers();
			startTurnMenu();
		}
	}

	outputCharacter(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), key);

	return key == 'c';
}

void trading(void)
{
	static char key;
	static long amount, temp;
	static long foodBuyPrice, acresBuyPrice;
	static long foodSellPrice, acresSellPrice;
	static bool done;

	// Buy/Sell Food
	done = false;
	foodBuyPrice = 3L;
	foodSellPrice = 1L;
	while(!done)
	{
		sprintf(buffer, EMPIRE_TRADE_ACRES, _currentEmpirePlayer.acres);
		outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), buffer);
		sprintf(buffer, EMPIRE_TRADE_FOOD, _currentEmpirePlayer.food);
		outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), buffer);
		sprintf(buffer, EMPIRE_TRADE_GOLD, _currentEmpirePlayer.gold);
		outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), buffer);

	
		key = 0;
		do
		{
			if(key == 0 || key == '?')
			{
				outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), EMPIRE_TRADE_FOOD_1);
				sprintf(buffer, EMPIRE_TRADE_FOOD_2, foodBuyPrice, foodSellPrice);
				outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), buffer);
				outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), EMPIRE_TRADE_FOOD_3);
			}
			key = tolower(inputChar(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), IO_ALPHA));
			if(key == '?') outputFile(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), 
				"empire.econ", &(bcd.bbsDirectory));
		} while(key != 's' && key != 'b' && key != 'n');

		outputCharacter(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), key);
		switch(key)
		{
		case 's':
			sprintf(buffer, EMPIRE_TRADE_HOW_MANY, _currentEmpirePlayer.food);
			outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), buffer);
			input(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), IO_NUMERIC, buffer, 7, false);
			amount = atol(buffer);
			if(amount > _currentEmpirePlayer.food)
			{
				outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), EMPIRE_TRADE_NOT_ENOUGH);
			}
			else
			{
				_currentEmpirePlayer.gold += amount * foodSellPrice;
				_currentEmpirePlayer.food -= amount;
				done = true;
			}
			break;
		case 'b':
			sprintf(buffer, EMPIRE_TRADE_HOW_MANY, _currentEmpirePlayer.gold / foodBuyPrice);
			outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), buffer);
			input(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), IO_NUMERIC, buffer, 7, false);
			amount = atol(buffer);
			if(amount * foodBuyPrice > _currentEmpirePlayer.gold)
			{
				outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), EMPIRE_TRADE_NOT_ENOUGH);
			}
			else
			{
				_currentEmpirePlayer.gold -= amount * foodBuyPrice;
				_currentEmpirePlayer.food += amount;
				done = true;
			}
			break;
		default:
			done = true;
			break;
		}
	}

	// Buy/Sell Acres
	done = false;
	acresBuyPrice = 300L;
	acresSellPrice = 100L;
	while(!done)
	{
		sprintf(buffer, EMPIRE_TRADE_ACRES, _currentEmpirePlayer.acres);
		outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), buffer);
		sprintf(buffer, EMPIRE_TRADE_FOOD, _currentEmpirePlayer.food);
		outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), buffer);
		sprintf(buffer, EMPIRE_TRADE_GOLD, _currentEmpirePlayer.gold);
		outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), buffer);

		key = 0;
	
		do
		{
			if(key == 0 || key == '?')
			{
				outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), EMPIRE_TRADE_ACRES_1);
				sprintf(buffer, EMPIRE_TRADE_ACRES_2, acresBuyPrice, acresSellPrice);
				outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), buffer);
				outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), EMPIRE_TRADE_ACRES_3);
			}
			key = tolower(inputChar(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), IO_ALPHA));
			if(key == '?') outputFile(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), 
				"empire.econ", &(bcd.bbsDirectory));
		} while(key != 's' && key != 'b' && key != 'n');

		outputCharacter(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), key);
		switch(key)
		{
		case 's':
			sprintf(buffer, EMPIRE_TRADE_HOW_MANY, _currentEmpirePlayer.acres);
			outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), buffer);
			input(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), IO_NUMERIC, buffer, 7, false);
			amount = atol(buffer);
			if(amount > _currentEmpirePlayer.acres)
			{
				outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), EMPIRE_TRADE_NOT_ENOUGH);
			}
			else
			{
				_currentEmpirePlayer.gold += amount * acresSellPrice;
				_currentEmpirePlayer.acres -= amount;
				done = true;
			}
			break;
		case 'b':
			sprintf(buffer, EMPIRE_TRADE_HOW_MANY, _currentEmpirePlayer.gold / acresBuyPrice);
			outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), buffer);
			input(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), IO_NUMERIC, buffer, 7, false);
			amount = atol(buffer);
			if(amount * acresBuyPrice > _currentEmpirePlayer.gold)
			{
				outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), EMPIRE_TRADE_NOT_ENOUGH);
			}
			else
			{
				_currentEmpirePlayer.gold =
					_currentEmpirePlayer.gold - (amount * acresBuyPrice);
				
				_currentEmpirePlayer.acres += amount;
				done = true;
			}
			break;
		default:
			done = true;
			break;
		}
	}


	return;
}

void buildingMenu(void)
{
		statsLine();
		outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), EMPIRE_BUILD_MENU_1);
		sprintf(buffer, EMPIRE_BUILD_MENU_3, _empireBuildings[EB_LUMBERMILL].goldRequired, _empireBuildings[EB_LUMBERMILL].lumberRequired, _empireBuildings[EB_LUMBERMILL].stoneRequired, _currentEmpirePlayer.lumbermills);
		outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), buffer);
		sprintf(buffer, EMPIRE_BUILD_MENU_4, _empireBuildings[EB_MINE].goldRequired, _empireBuildings[EB_MINE].lumberRequired, _empireBuildings[EB_MINE].stoneRequired, _currentEmpirePlayer.mines);
		outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), buffer);
		sprintf(buffer, EMPIRE_BUILD_MENU_5, _empireBuildings[EB_MARKET].goldRequired, _empireBuildings[EB_MARKET].lumberRequired, _empireBuildings[EB_MARKET].stoneRequired, _currentEmpirePlayer.markets);
		outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), buffer);
		sprintf(buffer, EMPIRE_BUILD_MENU_7, _empireBuildings[EB_FOUNDRY].goldRequired, _empireBuildings[EB_FOUNDRY].lumberRequired, _empireBuildings[EB_FOUNDRY].stoneRequired, _currentEmpirePlayer.foundries);
		outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), buffer);
		sprintf(buffer, EMPIRE_BUILD_MENU_6, _empireBuildings[EB_BROTHEL].goldRequired, _empireBuildings[EB_BROTHEL].lumberRequired, _empireBuildings[EB_BROTHEL].stoneRequired, _currentEmpirePlayer.brothels);
		outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), buffer);
		sprintf(buffer, EMPIRE_BUILD_MENU_8, _empireBuildings[EB_PUB].goldRequired, _empireBuildings[EB_PUB].lumberRequired, _empireBuildings[EB_PUB].stoneRequired, _currentEmpirePlayer.pubs);
		outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), buffer);
		sprintf(buffer, EMPIRE_BUILD_MENU_9, _empireBuildings[EB_BANK].goldRequired, _empireBuildings[EB_BANK].lumberRequired, _empireBuildings[EB_BANK].stoneRequired, _currentEmpirePlayer.banks);
		outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), buffer);
		outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), EMPIRE_BUILD_MENU_10);
}

void building(void)
{
	static char key;
	static int maxGold, maxWood, maxStone, max;
	static int amount;
	static empireBuildings_t buildingType;

	while(true)
	{
		buildingMenu();
		key = 0;
		while(!(key >='1' && key <='7') && key != 'n')
		{
			key = tolower(inputChar(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), IO_ALPHA_NUMERIC));
			if(key == '?')
			{
				outputFile(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), "empire.econ", &(bcd.bbsDirectory));
				buildingMenu();
			}
		}

		outputCharacter(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), key);

		if(key == 'n') break;

		buildingType = (empireBuildings_t)(key - 49);

		maxGold = _currentEmpirePlayer.gold / _empireBuildings[buildingType].goldRequired;
		maxWood = _currentEmpirePlayer.lumber / _empireBuildings[buildingType].lumberRequired;
		maxStone = _currentEmpirePlayer.stone / _empireBuildings[buildingType].stoneRequired;
		max = maxGold < maxWood && maxGold < maxStone ? maxGold
			: (maxWood < maxGold && maxWood < maxStone ? maxWood : maxStone);

		sprintf(buffer, EMPIRE_BUILD_HOW_MANY, max);
		outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), buffer);
		memset(buffer, 0, 81);
		input(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), IO_NUMERIC, buffer, 4, false);
		
		if(strlen(buffer) > 0)
		{
			amount = atoi(buffer);

			if(amount <= max)
			{
				_currentEmpirePlayer.gold -= amount * _empireBuildings[buildingType].goldRequired;
				_currentEmpirePlayer.lumber -= amount * _empireBuildings[buildingType].lumberRequired;
				_currentEmpirePlayer.stone -= amount * _empireBuildings[buildingType].stoneRequired;

				switch(buildingType)
				{
				case EB_LUMBERMILL:
					_currentEmpirePlayer.lumbermills += amount;
					break;
				case EB_MINE:
					_currentEmpirePlayer.mines += amount;
					break;
				case EB_MARKET:
					_currentEmpirePlayer.markets += amount;
					break;
				case EB_FOUNDRY:
					_currentEmpirePlayer.foundries += amount;
					break;
				case EB_BROTHEL:
					_currentEmpirePlayer.brothels += amount;
					break;
				case EB_PUB:
					_currentEmpirePlayer.pubs += amount;
					break;
				case EB_BANK:
					_currentEmpirePlayer.banks += amount;
					break;
				}
			}
			else
			{
				outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), EMPIRE_BUILD_NOT_NUFF);
			}
		}
	}

	return;
}

void trainingMenu(void)
{
		statsLine();
		outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), EMPIRE_TRAIN_MENU_1);
		outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), EMPIRE_TRAIN_MENU_2);
		sprintf(buffer, EMPIRE_TRAIN_MENU_3, _empireSettings.priceInfantry, _currentEmpirePlayer.Infantry);
		outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), buffer);
		sprintf(buffer, EMPIRE_TRAIN_MENU_4, _empireSettings.priceArcher, _currentEmpirePlayer.Archers);
		outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), buffer);
		sprintf(buffer, EMPIRE_TRAIN_MENU_5, _empireSettings.priceCavalry, _currentEmpirePlayer.Cavalry);
		outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), buffer);
		sprintf(buffer, EMPIRE_TRAIN_MENU_6, _empireSettings.priceCatapult, _currentEmpirePlayer.Catapults);
		outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), buffer);
		sprintf(buffer, EMPIRE_TRAIN_MENU_7, _empireSettings.priceKnight, _currentEmpirePlayer.Knights);
		outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), buffer);
		sprintf(buffer, EMPIRE_TRAIN_MENU_8, _empireSettings.priceNoble, _currentEmpirePlayer.Nobles);
		outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), buffer);
		outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), EMPIRE_TRAIN_MENU_9);
}

void training(void)
{
	static char key;
	static long price, max, perNoble, count;
	static long amount;
	static empireBuildings_t buildingType;

	while(true)
	{
		trainingMenu();
		key = 0;
		while(!(key >='1' && key <='6') && key != 'n')
		{
			key = tolower(inputChar(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), IO_ALPHA_NUMERIC));
			if(key == '?')
			{
				outputFile(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), "empire.com", &(bcd.bbsDirectory));
				trainingMenu();
			}
		}

		outputCharacter(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), key);

		if(key == 'n') break;

		switch(key)
		{
		case '1': price = _empireSettings.priceInfantry; perNoble = 40; count = _currentEmpirePlayer.Infantry; break;
		case '2': price = _empireSettings.priceArcher; perNoble = 40; count = _currentEmpirePlayer.Archers; break;
		case '3': price = _empireSettings.priceCavalry; perNoble = 20; count = _currentEmpirePlayer.Cavalry; break;
		case '4': price = _empireSettings.priceCatapult; perNoble = 5; count = _currentEmpirePlayer.Catapults; break;
		case '5': price = _empireSettings.priceKnight; perNoble = 8; count = _currentEmpirePlayer.Knights; break;
		case '6': price = _empireSettings.priceNoble; perNoble = 1000000; count = _currentEmpirePlayer.Nobles; break;
		}

		max = _currentEmpirePlayer.gold / price;
		if(max > (perNoble * _currentEmpirePlayer.Nobles - count))
		{
			max = (perNoble * _currentEmpirePlayer.Nobles - count);
		}

		sprintf(buffer, EMPIRE_TRAIN_HOW_MANY, max);
		outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), buffer);
		memset(buffer, 0, 81);
		input(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), IO_NUMERIC, buffer, 4, false);
		
		if(strlen(buffer) > 0)
		{
			amount = atoi(buffer);

			if(amount <= max)
			{
				_currentEmpirePlayer.gold -= amount * price;

				switch(key)
				{
				case '1': _currentEmpirePlayer.Infantry += amount; break;
				case '2': _currentEmpirePlayer.Archers += amount; break;
				case '3': _currentEmpirePlayer.Cavalry += amount; break;
				case '4': _currentEmpirePlayer.Catapults += amount; break;
				case '5': _currentEmpirePlayer.Knights += amount; break;
				case '6': _currentEmpirePlayer.Nobles += amount; break;
				}

				_empireSettings.players[_currentEmpirePlayer.playerNumber].might =
					calculateMight(&_currentEmpirePlayer);
			}
			else
			{
				outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), EMPIRE_BUILD_NOT_NUFF);
			}
		}
	}
	return;
}


void playGame(void)
{
	while(_currentEmpirePlayer.turnsRemaining > 0)
	{
		// Start Turn
		if(!startTurn()) break;
		_currentEmpirePlayer.turnsRemaining--;

		// Production
		production();

		// Trading
		trading();

		// Building
		building();

		// Training
		training();
		
		// Conquest
		loadOverlay("bbs.empirec", &conquest, "bbs.empire");

		// Quest

		//_currentEmpirePlayer.lastPlayed = _systime() + _baseTime;
		if(savePlayer(&_currentEmpirePlayer))
		{
			saveSettings();
		}

		outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), CRLF);
		pause(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM));
	}

	if(_currentEmpirePlayer.turnsRemaining == 0)
	{
		outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), EMPIRE_NO_MORE_TURNS);
	}
	else
	{
		sprintf(buffer, EMPIRE_TURNS_REMAINING, _currentEmpirePlayer.turnsRemaining);
		outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), buffer);
	}
}

bool savePlayer(empirePlayer_t *player)
{
	static bool result;
	static FILE *file;
	static char oldDirectory[17];
	static char directory[17];
	static char filename[21];

	//getcwd(oldDirectory, 17);
	getdevicedir(bcd.dataDirectory.device, directory, 17);
	chdir(directory);

	sprintf(filename, "emp-plr-%04X", player->playerNumber);

	file = fopen(filename, "wb");

	if(file != NULL)
	{
		result = (bool)fwrite(player, sizeof(empirePlayer_t), 1, file);
	}
	else
	{
		result = false;
	}

	fclose(file);

	//chdir(oldDirectory);

	if(result) outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), EMPIRE_PLAYER_SAVED);
	else 
	{
		sprintf(buffer, "Error saving player: %u", _oserror);
		outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), buffer);
	}

	return result;
}

bool initPlayer(void)
{
	static empirePlayerIdxRec_t *idxRec;

	if(_empireSettings.numberOfPlayers >= EMPIRE_MAX_PLAYERS) return false;

	memset(&_currentEmpirePlayer, 0, sizeof(empirePlayer_t));

	outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), EMPIRE_KINGDOM_NAME_1);
	input(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), IO_ALPHA_NUMERIC, _currentEmpirePlayer.kingdomName, 20, false);

	_currentEmpirePlayer.playerNumber = _empireSettings.numberOfPlayers++;
	_currentEmpirePlayer.userNumber = _currentUser.usernumber;
	_currentEmpirePlayer.taxRate = 10;
	_currentEmpirePlayer.gold = _empireSettings.startingGold;
	_currentEmpirePlayer.acres = _empireSettings.startingAcres;
	_currentEmpirePlayer.lumber = _empireSettings.startingLumber;
	_currentEmpirePlayer.food = 0;
	_currentEmpirePlayer.stone = _empireSettings.startingStone;
	_currentEmpirePlayer.peasants = _empireSettings.startingPeasants;
	_currentEmpirePlayer.lastPlayed = _systime() + _baseTime;
	_currentEmpirePlayer.turnsRemaining = _empireSettings.turnsPerDay;

	_currentEmpirePlayer.Infantry = _empireSettings.startingInfantry;
	_currentEmpirePlayer.Archers = _empireSettings.startingArchers;
	_currentEmpirePlayer.Cavalry = _empireSettings.startingCavalry;
	_currentEmpirePlayer.Catapults = _empireSettings.startingCatapults;
	_currentEmpirePlayer.Knights = _empireSettings.startingKnights;
	_currentEmpirePlayer.Nobles = _empireSettings.startingNobles;

	_currentEmpirePlayer.lumbermills = 5;
	_currentEmpirePlayer.mines = 5;

	_empireSettings.totalAcres += _currentEmpirePlayer.acres;
	_empireSettings.totalArchers += _currentEmpirePlayer.Archers;
	_empireSettings.totalCatapults += _currentEmpirePlayer.Catapults;
	_empireSettings.totalCavalry += _currentEmpirePlayer.Cavalry;
	_empireSettings.totalGold += _currentEmpirePlayer.gold;
	_empireSettings.totalInfantry += _currentEmpirePlayer.Infantry;
	_empireSettings.totalKnights += _currentEmpirePlayer.Knights;
	_empireSettings.totalNobles += _currentEmpirePlayer.Nobles;
	_empireSettings.totalPeasants += _currentEmpirePlayer.peasants;

	idxRec = &_empireSettings.players[_currentEmpirePlayer.playerNumber];
	idxRec->userNumber = _currentUser.usernumber;
	strcpy(idxRec->alias, _currentUser.decorated_username);
	strcpy(idxRec->kingdonName, _currentEmpirePlayer.kingdomName);
	idxRec->acres = _currentEmpirePlayer.acres;
	idxRec->gold = _currentEmpirePlayer.gold;
	idxRec->might = calculateMight(&_currentEmpirePlayer);
	
	outputFile(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), 
		"empire.new", &(bcd.bbsDirectory));

	if(savePlayer(&_currentEmpirePlayer))
	{
		return saveSettings();
	}

	return false;
}

long calculateMight(empirePlayer_t *player)
{
	long result = 
		player->Infantry + 
		player->Archers +
		player->Cavalry * 2L +
		player->Catapults * 10L +
		player->Knights * 5L ;	

	return result;
}

void loadSettings(void)
{
	static FILE *file;
	static char oldDirectory[17];
	static char directory[17];
	static char filename[21];

	//getcwd(oldDirectory, 17);
	getdevicedir(bcd.dataDirectory.device, directory, 17);
	chdir(directory);

	file = fopen("empire-settings", "rb");

	memset(&_empireSettings, 0, sizeof(empire_t));

	if(file != NULL)
	{
		fread(&_empireSettings, sizeof(empire_t), 1, file);
		outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), EMPIRE_LOADED);
	}
	else
	{
		initSettings();
		outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), EMPIRE_INITIALIZED);
	}

	fclose(file);

	//chdir(oldDirectory);
	

}

void initSettings(void)
{
	outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), EMPIRE_UNITIALIZED_1);
	outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), EMPIRE_UNITIALIZED_2);

	// TODO: SYSOPS - Customize your game here
	_empireSettings.startedOn = _systime() + _baseTime;
	_empireSettings.numberOfPlayers = 0;
	_empireSettings.turnsPerDay = 5;					// TODO: Sysops - This is very much up to you
	
	_empireSettings.startingAcres = 2000;
	_empireSettings.startingPeasants = 1000;
	_empireSettings.startingLumber = 500;
	_empireSettings.startingStone = 500;
	_empireSettings.startingGold = 500;
	
	_empireSettings.startingInfantry = 10;
	_empireSettings.startingArchers = 10;
	_empireSettings.startingCavalry = 5;
	_empireSettings.startingCatapults = 0;
	_empireSettings.startingKnights = 2;
	_empireSettings.startingNobles = 1;

	_empireSettings.priceArcher = 30;
	_empireSettings.priceInfantry = 25;
	_empireSettings.priceCavalry = 90;
	_empireSettings.priceCatapult = 300;
	_empireSettings.priceKnight = 160;
	_empireSettings.priceNoble = 2500;
}

bool saveSettings(void)
{
	bool result = false;
	static FILE *file;
	static char oldDirectory[17];
	static char directory[17];
	static char filename[21];

	//getcwd(oldDirectory, 17);
	getdevicedir(bcd.dataDirectory.device, directory, 17);
	chdir(directory);

	file = fopen("empire-settings", "wb");

	if(file != NULL)
	{
		if(fwrite(&_empireSettings, sizeof(empire_t), 1, file)==1)
		{
			result = true;
		}
	}

	fclose(file);

	//chdir(oldDirectory);

	return result;
}

bool loadPlayer(empirePlayer_t *player, int playerNumber)
{
	static bool result;
	static FILE *file;
	static char oldDirectory[17];
	static char directory[17];
	static char filename[21];
	static char time1[13];
	static char time2[13];
	static struct tm *temp;
	static long yday1, yday2;
	static long year1, year2;
	static time_t currentTime;
	static char i;
	static char tbuffer[12];

	result = false;

	//getcwd(oldDirectory, 17);
	getdevicedir(bcd.dataDirectory.device, directory, 17);
	chdir(directory);

	sprintf(filename, "emp-plr-%04X", playerNumber);

	file = fopen(filename, "rb");

	if(file != NULL)
	{
		result = (bool)fread(player, sizeof(empirePlayer_t), 1, file);
	}

	fclose(file);

	//chdir(oldDirectory);

	if(result)
	{
		if(player->wipedOutOn > 0)
		{
			strftime(tbuffer, 12, "%I:%M:%S %p", localtime(&(player->wipedOutOn)));
			sprintf(buffer, EMPIRE_WIPED_OUT_ON, player->wipedOutBy, tbuffer);
			outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), CRLF);
			outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), buffer);
		}

		if(player == &_currentEmpirePlayer)
		{
			temp = localtime(&(_currentEmpirePlayer.lastPlayed));
			yday1 = temp->tm_yday;
			year1 = temp->tm_year;

			currentTime = (_systime() + _baseTime);
			temp = localtime(&currentTime);
			yday2 = temp->tm_yday;
			year2 = temp->tm_year;

			if(yday1 != yday2 || year1 != year2)
			{
				player->lastPlayed = _systime() + _baseTime;
				player->turnsRemaining = _empireSettings.turnsPerDay;
				outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), EMPIRE_NEW_DAY);

				for(i = 0; i < EMPIRE_MAX_PLAYERS; ++i)
				{
					player->attackedToday[i] = false;
				}
			}
		}
	}
	else
	{
		outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), CRLF CHX_RED "Could not load player record.");
	}
	return result;
}

void statsLine(void)
{
	sprintf(buffer, EMPIRE_STATS_LINE_1, _currentEmpirePlayer.gold);
	outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), buffer);
	sprintf(buffer, EMPIRE_STATS_LINE_2, _currentEmpirePlayer.acres);
	outputString(PLATFORM_ENCODING, (outDirections_t)(OD_SCREEN | OD_MODEM), buffer);
}